1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.error.handler; 12 import hip.console.log; 13 import hip.util.conv; 14 15 /** 16 * Base clas for documenting errors 17 */ 18 19 public class EngineErrorStack 20 { 21 public string stackName; 22 public string[] errorStack; 23 24 private this(string stackName) 25 { 26 this.stackName = stackName; 27 } 28 29 public static EngineErrorStack getNewStack(string stackName) 30 { 31 return new EngineErrorStack(stackName); 32 } 33 /** 34 * Adds an error to the stack 35 * Params: 36 * errorHeader = Error Short 37 * errorMessage = Error Long 38 */ 39 public void addError(string errorHeader, string errorMessage) 40 { 41 errorStack~= errorHeader ~ ": " ~ errorMessage; 42 } 43 44 public void showStack() 45 { 46 rawerror("ErrorStack: " ~ stackName); 47 const int len = cast(int)this.errorStack.length; 48 for(int i = 0; i < len; i++) 49 rawerror("\t" ~ errorStack[i]); 50 } 51 } 52 53 54 import core.stdc.stdlib; 55 56 version(iOS) 57 { 58 extern(C) void terminateiOSApp(int code); 59 ///iOS has a special terminate function which ought to be called when something happens. 60 alias terminate = terminateiOSApp; 61 } 62 else 63 { 64 alias terminate = core.stdc.stdlib.exit; 65 } 66 67 /** 68 * Class Used for handling errors 69 */ 70 public static class ErrorHandler 71 { 72 __gshared 73 { 74 private bool HAS_ANY_ERROR_HAPPENNED = false; 75 private EngineErrorStack currentStack; 76 private EngineErrorStack[] stackHistory; 77 private string[] warnHistory; 78 private bool isListening = false; 79 public string LAST_ERROR = ""; 80 } 81 82 /** 83 * This function will look wether any error has happenned 84 * stackName = This will help identify where the error ocurred 85 */ 86 public static void startListeningForErrors(string stackName = "Default Error") 87 { 88 if(isListening) 89 stopListeningForErrors(); 90 HAS_ANY_ERROR_HAPPENNED = false; 91 isListening = true; 92 currentStack = EngineErrorStack.getNewStack(stackName); 93 } 94 /** 95 * Will stop listening and 96 * Returns: HAS_ANY_ERROR_HAPPENNED 97 */ 98 public static bool stopListeningForErrors() 99 { 100 if(HAS_ANY_ERROR_HAPPENNED) 101 stackHistory~= currentStack; 102 currentStack = null; 103 isListening = false; 104 return HAS_ANY_ERROR_HAPPENNED; 105 } 106 107 private static void getError(lazy string errorHeader, lazy string error) 108 { 109 if(isListening) 110 { 111 LAST_ERROR = errorHeader ~ ": \n" ~ error; 112 currentStack.addError(errorHeader, error); 113 } 114 } 115 116 117 /** 118 * This function adds to the error stack 119 * Params: 120 * errorTitle = Error Header 121 * errorMessage = Error Message 122 */ 123 public static void showErrorMessage(string errorTitle, string errorMessage, bool isFatal = false) 124 { 125 import hip.util.string; 126 if(isFatal) 127 { 128 rawfatal(BigString(errorTitle, "\t[[", errorMessage, "]]").toString); 129 } 130 else 131 { 132 rawerror(BigString(errorTitle, "\t[[", errorMessage, "]]").toString); 133 } 134 getError(errorTitle, errorMessage); 135 } 136 public static void showWarningMessage(string warningTitle, string warningMessage) 137 { 138 rawwarn("\nWarning: " ~ warningTitle); 139 rawwarn(warningMessage); 140 warnHistory~= warningTitle~": "~warningMessage; 141 } 142 143 /** 144 * 145 * Params: 146 * expression = Expression for looking wether an error has happenned 147 * errorTitle = Error Header 148 * errorMessage = Error Message 149 * Returns: If the error happenned 150 */ 151 public static bool assertErrorMessage(bool expression, string errorTitle, string errorMessage, bool isFatal = false, 152 string file = __FILE__, size_t line =__LINE__, string mod = __MODULE__, string func = __PRETTY_FUNCTION__) 153 { 154 import hip.util.string; 155 expression = !expression; //Negate the expression, as it must return wether error ocurred 156 if(expression) 157 { 158 String where; 159 version(HIPREME_DEBUG) 160 { 161 where = String("at module '", mod, "' ", file, ":", line, "(", func, ")\n\t"); 162 } 163 164 showErrorMessage(String(where, errorTitle).toString, errorMessage, isFatal); 165 } 166 return expression; 167 } 168 169 /** 170 * 171 * Params: 172 * expression = Expression for looking wether an error has happenned 173 * errorTitle = Error Header 174 * errorMessage = Error Message 175 * Returns: If the error happenned 176 */ 177 public static bool assertLazyErrorMessage(bool expression, lazy string errorTitle, lazy string errorMessage, bool isFatal = false, 178 string file = __FILE__, size_t line =__LINE__, string mod = __MODULE__, string func = __PRETTY_FUNCTION__) 179 { 180 expression = !expression; //Negate the expression, as it must return wether error ocurred 181 if(expression) 182 { 183 version(HIPREME_DEBUG) 184 { 185 string where = "at module '"~mod~"' "~file~":"~to!string(line)~"("~func~")\n\t"; 186 } 187 else{string where="";} 188 showErrorMessage(where~errorTitle, errorMessage, isFatal); 189 } 190 return expression; 191 } 192 193 /** 194 * If you're running on a loop or need to concat your failure message, prefer using assertLazyExit. 195 */ 196 public static void assertExit(bool expression, string onAssertionFailure = "Assertion Failure", 197 string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__, string func = __PRETTY_FUNCTION__) 198 { 199 if(!expression) 200 { 201 cast(void)ErrorHandler.assertErrorMessage(false, "HipAssertion", onAssertionFailure, true, 202 file, line, mod, func); 203 terminate(EXIT_FAILURE); 204 } 205 } 206 207 public static void assertLazyExit(bool expression, lazy string onAssertionFailure, 208 string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__, string func = __PRETTY_FUNCTION__) 209 { 210 if(!expression) 211 { 212 cast(void)ErrorHandler.assertLazyErrorMessage(false, "HipAssertion", onAssertionFailure, true, 213 file, line, mod, func); 214 terminate(EXIT_FAILURE); 215 } 216 } 217 218 static immutable(string) assertReturn(string expression)(string onAssertionFailureMessage) 219 { 220 return `if(ErrorHandler.assertErrorMessage(`~expression~`, "HipAssertion", "`~onAssertionFailureMessage~ 221 `"))return;`; 222 } 223 224 public static void showEveryError() 225 { 226 foreach(stack; stackHistory) 227 { 228 stack.showStack(); 229 } 230 } 231 }